/*
 * Grid.cpp
 *
 *  Created on: 2 oct. 2009
 *      Author: Jey
 */

#include "Grid.h"
#include <iostream>
#include <fstream>
#include <math.h>
using namespace std;

	// Constructeur avec initialisation de la node
	Grid::Grid()
	{
			ImportGrid("/home/titi/Documents/File.lab");
	}

	// Destructeur
	Grid::~Grid() {}

	// Récupérer le nombre de colonne
	int Grid::GetNbColumn()
	{
		return NbColumn;
	}

	// Récupérer le nombre de ligne
	int Grid::GetNbLine()
	{
		return NbLine;
	}

	// Vérifier si la valeur d'une node est fixée
	bool Grid::IsFixed(int x)
	{
		return(GridVector[x] -> IsFixed());
	}

	// Importer une grille à partir d'un fichier
	void Grid::ImportGrid(string Filename)
	{
		int TempValue;

		// Ouverture du fichier
		ifstream File;
		File.open("/home/titi/Documents/File.lab");
		if(!File)
		{
			cout<<"Error missing File!"<<endl;
		}

		// Lecture de la taille de la grille
		File >> NbLine;
		NbColumn = NbLine;

		// Récupération du fichier dans la grille temporaire
		for(int i = 0; i < NbLine*NbColumn; i++)
		{
			File >> TempValue;
			if(TempValue == 0)
			{
				GridVector.push_back(new Node());
				GridVector[i] -> InitValues(NbColumn);
			}
			else
				GridVector.push_back(new Node(TempValue));
		}

		// Fermeture du fichier
		File.close();
	}

	// Afficher une grille à l'écran
	void Grid::ExportGrid()
	{
		for(int i = 0; i < NbLine*NbColumn; i++)
		{
			if(i%NbColumn == 0)
				cout << endl;
			if(GridVector[i] -> IsFixed() == true && GridVector[i] -> GetTempValueFixed() == false)
				cout << (GridVector[i] -> GetValue(0)) << " ";
			else if(GridVector[i] -> GetTempValueFixed() == true)
				cout << (GridVector[i] -> GetTempValue()) << " ";
			else
				cout << "0" << " ";
		}
	}


	// Mettre à jour les valeurs possible de la node en fonction des valeurs de la ligne
	void Grid::CheckLine(int x)
	{
		// Index dans le vecteur
		int IndexLine;

		// Variable d'identification de la colonne
		int NumColumn;

		// Variable d'identification de la ligne
		int NumLine;

		// Variable contenant le nombre de valeurs possible de la node
		int ValueCount;

		// Vecteur contenant les valeurs à éliminer de la liste des valeurs possible de la node
		vector<int>TempVector;

		// Calcul du numéro de la colonne dans laquelle se trouve la node à tester
		if(x < NbLine)
			NumColumn = x;
		else
			NumColumn = x%NbLine;

		// Calcul du numéro de la ligne dans laquelle se trouve la node à tester
		NumLine = (x - NumColumn) / NbLine;

		// Calcul du nombre de valeur possible pour la node
		ValueCount = GridVector[x] -> GetValueCount();

		if(GridVector[x] -> IsFixed() == false)
		{
		// Remplissage du vecteur contenant les valeurs à éliminer de la liste des valeurs possibles de la node
			for(int j = 0; j < NbLine; j++)
			{
				IndexLine = j + NumLine * NbColumn;
				if(IndexLine != x)
					if(GridVector[IndexLine] -> IsFixed() == true)
						for(int k = 0; k < ValueCount; k++)
							if((GridVector[x] -> GetValue(k)) == (GridVector[IndexLine] -> GetValue(0)))
								TempVector.push_back((GridVector[IndexLine] -> GetValue(0)));
			}

		// Mise à jour de la liste des valeurs possible de la node
			for(unsigned int l = 0; l < TempVector.size(); l++)
				if(GridVector[x] -> IsFixed() == false)
					GridVector[x] -> RmValue(TempVector[l]);
				else
					cout<<"Error line "<<x<<endl;
		}
		else
			cout << "Error Value fixed" << endl;
	}


	// Mettre à jour les valeurs possible de la node en fonction des valeurs de la colonne
	void Grid::CheckColumn(int x)
	{
		// Index dans le vecteur
		int IndexColumn;

		// Variable d'identification de la colonne
		int NumColumn;

		// Variable contenant le nombre de valeurs possible de la node
		int ValueCount;

		// Vecteur contenant les valeurs à éliminer de la liste des valeurs possible de la node
		vector<int>TempVector;

		// Calcul du numéro de la colonne dans laquelle se trouve la node à tester
		if(x < NbColumn)
			NumColumn = x;
		else
			NumColumn = x%NbColumn;

		// Calcul du nombre de valeur possible pour la node
		ValueCount = GridVector[x] -> GetValueCount();

		if(GridVector[x] -> IsFixed() == false)
		{
		// Remplissage du vecteur contenant les valeurs à éliminer de la liste des valeurs possibles de la node
			for(int j = 0; j < NbLine; j++)
			{
				IndexColumn = NumColumn + j * NbColumn;
				if(IndexColumn != x)
					if(GridVector[IndexColumn] -> IsFixed() == true)
						for(int k = 0; k < ValueCount; k++)
							if((GridVector[x] -> GetValue(k)) == (GridVector[IndexColumn] -> GetValue(0)))
								TempVector.push_back((GridVector[IndexColumn] -> GetValue(0)));
			}

		// Mise à jour de la liste des valeurs possible de la node
			for(unsigned int l = 0; l < TempVector.size(); l++)
				if(GridVector[x] -> IsFixed() == false)
					GridVector[x] -> RmValue(TempVector[l]);
				else
					cout<<"Error colonne "<<x<<endl;
		}
		else
			cout << "Error Value already fixed" << endl;
	}


	// Mettre à jour les valeurs possibles de la node en focntion des valeurs du carré
	void Grid::CheckSquare(int x)
	{
		// Variable contenant le nombre de valeurs possible de la node
		int ValueCount;

		// Variable d'identification de la ligne
		int NumLine;

		// Variable d'identification de la colonne
		int NumColumn;

		// Variable d'indentification de la ligne de la première case du carré
		int NumLineSquare = 1;

		// Variable d'indentification de la colonne de la première case du carré
		int NumColumnSquare = 1;

		// Variable d'identification de l'index d'une case du carré dans le vecteur
		int IndexSquare;

		// Vecteur contenant les valeurs à éliminer de la liste des valeurs possible de la node
		vector<int>TempVector;

		// Calcul du numéro de la colonne dans laquelle se trouve la node à tester
				if(x < NbColumn)
					NumColumn = x;
				else
					NumColumn = x%NbColumn;

		// Calcul du numéro de la ligne dans laquelle se trouve la node à tester
		NumLine = (x - NumColumn) / NbLine;

		// Calcul du numéro de la colonne de la première case du carré
		while(NumColumn >= NumColumnSquare * sqrt(NbColumn))
			NumColumnSquare++;

		NumColumnSquare = (NumColumnSquare -1) * sqrt(NbColumn);

		// Calcul du numéro de la ligne de la première case du carré
		while(NumLine >= NumLineSquare * sqrt(NbLine))
			NumLineSquare++;

		NumLineSquare = (NumLineSquare -1) * sqrt(NbLine);

		// Calcul du nombre de valeur possible pour la node
		ValueCount = GridVector[x] -> GetValueCount();

		if(GridVector[x] -> IsFixed() == false)
		{
		// Remplissage du vecteur contenant les valeurs à éliminer de la liste des valeurs possibles de la node
			for(int i = NumLineSquare; i < NumLineSquare + sqrt(NbLine); i++)
				for(int j = NumColumnSquare; j < NumColumnSquare + sqrt(NbColumn); j++)
				{
					IndexSquare = j + i * NbColumn;
					if(IndexSquare != x)
						if(GridVector[IndexSquare] -> IsFixed() == true)
							for(int k = 0; k < ValueCount; k++)
								if((GridVector[x] -> GetValue(k)) == (GridVector[IndexSquare] -> GetValue(0)))
									TempVector.push_back((GridVector[IndexSquare] -> GetValue(0)));
				}

		// Mise à jour de la liste des valeurs possible de la node
			for(unsigned int l = 0; l < TempVector.size(); l++)
				if(GridVector[x] -> IsFixed() == false)
					GridVector[x] -> RmValue(TempVector[l]);
				else
					cout<<"Error square "<<x<<endl;
		}
		else
			cout << "Error Value already fixed" << endl;
	}

	bool Grid::Contradict(int x)
	{
		// Variable d'identification de la ligne
		int NumLine;

		// Variable d'identification de la colonne
		int NumColumn;

		// Index de la node
		int Index;

		// Variable d'indentification de la ligne de la première case du carré
		int NumLineSquare = 1;

		// Variable d'indentification de la colonne de la première case du carré
		int NumColumnSquare = 1;

		// Calcul du numéro de la colonne dans laquelle se trouve la node à tester
		if(x < NbColumn)
			NumColumn = x;
		else
			NumColumn = x%NbColumn;

		// Calcul du numéro de la ligne dans laquelle se trouve la node à tester
		NumLine = (x - NumColumn) / NbLine;

		if(GridVector[x] -> IsFixed() == false)
		{
			for(int i = 0; i < NbLine; i++)
			{
				Index = i + NumLine * NbColumn;
				if(Index != x)
					if(GridVector[Index] -> GetTempValueFixed() == true)
						if((GridVector[x] -> GetTempValue()) == (GridVector[Index] -> GetTempValue()))
							return true;
			}
		}
		else
			cout << "Error Value already fixed" << endl;


		if(GridVector[x] -> IsFixed() == false)
		{
			for(int j = 0; j < NbLine; j++)
			{
				Index = NumColumn + j * NbColumn;
				if(Index != x)
					if(GridVector[Index] -> GetTempValueFixed() == true)
						if((GridVector[x] -> GetTempValue()) == (GridVector[Index] -> GetTempValue()))
							return true;
			}
		}
		else
			cout << "Error Value already fixed" << endl;


		// Calcul du numéro de la colonne de la première case du carré
		while(NumColumn >= NumColumnSquare * sqrt(NbColumn))
			NumColumnSquare++;

		NumColumnSquare = (NumColumnSquare - 1) * sqrt(NbColumn);

		// Calcul du numéro de la ligne de la première case du carré
		while(NumLine >= NumLineSquare * sqrt(NbLine))
			NumLineSquare++;

		NumLineSquare = (NumLineSquare -1) * sqrt(NbLine);

		if(GridVector[x] -> IsFixed() == false)
		{
			for(int k = NumLineSquare; k < NumLineSquare + sqrt(NbLine); k++)
				for(int l = NumColumnSquare; l < NumColumnSquare + sqrt(NbColumn); l++)
				{
					Index = l + k * NbColumn;
						if(Index != x)
							if(GridVector[Index] -> GetTempValueFixed() == true)
								if((GridVector[x] -> GetTempValue()) == (GridVector[Index] -> GetTempValue()))
									return true;
				}
		}
		else
			cout << "Error Value already fixed" << endl;

		return false;

	}



	void Grid::BackTrack(int x)
	{
		if(GridVector[x] -> IsFixed() == false)
		{

			while(Contradict(x) == true && GridVector[x] -> GetTempValue() < NbLine)
			{
				GridVector[x] -> SetTempValue(NbLine);
			}


			if(Contradict(x) == true && GridVector[x] -> GetTempValue() == NbLine)
			{
				GridVector[x] -> SetTempValueFixed(false);
				GridVector[x] -> ResetTempValue();

				x--;
				while(GridVector[x] -> GetTempValue() == NbLine || GridVector[x] -> IsFixed() == true)
				{
					if(GridVector[x] -> IsFixed() == true)
						x--;
					else if(GridVector[x] -> GetTempValue() == NbLine)
					{
						GridVector[x] -> SetTempValueFixed(false);
						GridVector[x] -> ResetTempValue();
						x--;
					}
				}

				GridVector[x] -> SetTempValue(NbLine);
				BackTrack(x);
			}
			else
			{
				GridVector[x] -> SetTempValueFixed(true);
				x++;
				if(x != NbLine * NbColumn )
					BackTrack(x);
			}
		}
		else
		{
			GridVector[x] -> SetTempValueFixed(true);
			x++;
			if(x != NbLine * NbColumn )
				BackTrack(x);
		}
	}








